package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.tbit.common.entity.vo.MainLogAuditBatchVo;
import com.tbit.uqbike.constant.WorkType;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.WorkOrderLogQueryDTO;
import com.tbit.common.entity.pojo.dto.BarChartDispatchLogDTO;
import com.tbit.common.entity.pojo.vo.DateResult;
import com.tbit.uqbike.object.pojo.statistics.DispatchLog;
import com.tbit.uqbike.object.pojo.statistics.ExportPowerLog;
import com.tbit.common.entity.vo.MainLogAuditVo;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.service.business.AccountConfigExtService;
import com.tbit.uqbike.service.business.AccountUserService;
import com.tbit.uqbike.service.business.DispatchLogService;
import com.tbit.uqbike.webmanager.business.machine_op_log.service.MachineOpLogService;
import com.tbit.uqbike.webmanager.business.maintain_performance.service.DispatchPerformanceService;
import com.tbit.uqbike.webmanager.dao.core.AccountUserDao;
import com.tbit.uqbike.webmanager.dao.core.MachineDao;
import com.tbit.uqbike.webmanager.dao.core.PowerChangeMonitorConfigMapper;
import com.tbit.uqbike.webmanager.dao.core.WorkOrderDao;
import com.tbit.uqbike.webmanager.dao.log.DispatchLogDao;
import com.tbit.uqbike.webmanager.util.StringUtil;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: chen
 * @Description: 调度记录统计
 * @Date: 创建于 11:19 2020/3/13
 */
@Slf4j
@Service("dispatchLogService")
public class DispatchLogServiceImpl implements DispatchLogService {
    @Autowired
    private DispatchLogDao dispatchLogDao;
    @Autowired
    private AccountUserService accountUserService;
    @Autowired
    private AccountUserDao accountUserDao;
    @Autowired
    private WorkOrderDao workOrderDao;
    @Autowired
    private PowerChangeMonitorConfigMapper monitorConfigMapper;
    @Autowired
    private MachineOpLogService machineOpLogService;
    @Autowired
    private MachineDao machineDao;
    @Autowired
    private DispatchPerformanceService performanceService;
    @Autowired
    AccountConfigExtService accountConfigExtService;

    /**
     * 调度次数日期统计
     * @param barChartDispatchLogDTO 统计参数
     * @return  List
     */
    @Override
    public List<List<DateResult>> statisticsByTime(BarChartDispatchLogDTO barChartDispatchLogDTO) {

        //定义返回结果
        List<List<DateResult>> totalList = new ArrayList<>();
        barChartDispatchLogDTO.setValidList(StringUtil.getIntegerList(barChartDispatchLogDTO.getIsValid()));


        //获取传入时间每天的日期
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> findTimeList = DateTimeUtil.findDaysStr(simpleDateFormat.format(new Date(barChartDispatchLogDTO.getStartTime())), simpleDateFormat.format(new Date(barChartDispatchLogDTO.getEndTime())));
        //查询区域统计数据
        barChartDispatchLogDTO.setStartDate(new Date(barChartDispatchLogDTO.getStartTime()));
        barChartDispatchLogDTO.setEndDate(new Date(barChartDispatchLogDTO.getEndTime()));
        List<DateResult> results = dispatchLogDao.statisticsByTime(barChartDispatchLogDTO);
        //获取查询数据的日期集合
        List<String> dateList = results.stream().map(DateResult::getDate).collect(Collectors.toList());
        //得到传入时间和查询数据日期集合的差集
        List<String> reduce = findTimeList.stream().filter(item -> !dateList.contains(item)).collect(Collectors.toList());
        //进行补0
        if (!NullUtils.isEmpty(reduce)) {
            for (String date : reduce) {
                DateResult dateResult = new DateResult();
                dateResult.setDate(date);
                dateResult.setTotal(0);
                results.add(dateResult);
            }
        }
        /**根据日期排序*/
        results = results.stream().sorted(Comparator.comparing(DateResult::getDate)).collect(Collectors.toList());
        totalList.add(results);


        //获取运营区的所有分区id
        List<Region> list = accountUserDao.getRegionId(barChartDispatchLogDTO.getAccountId());
        barChartDispatchLogDTO.setRegionIds(list.stream().map(Region::getRegionId).collect(Collectors.toList()));
        List<DateResult> allRegionList = dispatchLogDao.statisticsByTimeAndRegionId(barChartDispatchLogDTO);
        Map<Integer, List<DateResult>> map = allRegionList.stream().collect(Collectors.groupingBy(DateResult::getRegionId));
        for (DateResult dateResult : allRegionList) {
            List<DateResult> dateResults = map.get(dateResult.getRegionId());
            if (CollectionUtil.isEmpty(dateResults)) {
                dateResults = new ArrayList<>();
                dateResults.add(dateResult);
                map.put(dateResult.getRegionId(), dateResults);
            }else {
                dateResults.add(dateResult);
            }
        }

        for (Region region : list) {
            results = CollectionUtil.isEmpty(map.get(region.getRegionId())) ? new ArrayList<>() : map.get(region.getRegionId());
            //获取查询数据的日期集合
            List<String> regionList = results.stream().map(DateResult::getDate).collect(Collectors.toList());
            //得到传入时间和查询数据日期集合的差集
            List<String> reduceRegion = findTimeList.stream().filter(item -> !regionList.contains(item)).collect(Collectors.toList());
            //进行补0
            if (!NullUtils.isEmpty(reduce)) {
                for (String date : reduceRegion) {
                    DateResult dateResult = new DateResult();
                    dateResult.setDate(date);
                    dateResult.setTotal(0);
                    results.add(dateResult);
                }
            }
            for (DateResult result : results) {
                result.setRegionId(region.getRegionId());
                if (region.getRegionId().equals(result.getRegionId())) {
                    result.setRegionName(region.getRegionName());
                }
            }
            //根据日期排序
            List<DateResult> collect = results.stream().sorted(Comparator.comparing(DateResult::getDate)).collect(Collectors.toList());
            totalList.add(collect);
        }
        totalList.removeIf(NullUtils::isEmpty);
        return totalList;
    }

    @Override
    public List<DispatchLog> queryPage(WorkOrderLogQueryDTO queryDTO) {
        Integer accountId = queryDTO.getAccountId();
        List<DispatchLog> logs = dispatchLogDao.queryPage(queryDTO);

        List<AccountUser> list = accountUserService.getByType(accountId, false);
        PowerChangeMonitorConfig monitorConfig = Optional.ofNullable(monitorConfigMapper.selectById(accountId))
                .orElseGet(() -> new PowerChangeMonitorConfig().putDefaultValue(accountId));
        Map<Integer, AccountUser> accountUserMap = new HashMap<>();
        if (list != null && list.size() > 0) {
            for (AccountUser accountUser : list) {
                accountUserMap.put(accountUser.getAccountUserId(), accountUser);
            }
        }
        /**将名称和电话号码补齐*/
        if (!NullUtils.isEmpty(logs)) {
            for (DispatchLog dispatchLog : logs) {
                /**运维人员信息*/
                AccountUser accountUser = accountUserMap.get(dispatchLog.getAccountUserId());
                if (accountUser != null) {
                    dispatchLog.setName(accountUser.getName());
                    dispatchLog.setPhone(accountUser.getPhone());
                }
                /**审核人信息*/
                AccountUser auditUser = accountUserMap.get(dispatchLog.getAuditorId());
                if (!NullUtils.isEmpty(auditUser)) {
                    dispatchLog.setAuditName(auditUser.getName());
                }
                dispatchLog.setDispatchRange(monitorConfig.matchDispatchRange(dispatchLog.getIdleTime()));
            }
        }
        return logs;
    }

    private Map<String, String> getDispatchWorkOrderMap(List<DispatchLog> logs) {
        return Optional.of(logs)
                .map(x -> x.stream().map(DispatchLog::getDispatchLogId).collect(Collectors.toList()))
                .filter(CollectionUtils::isNotEmpty)
                .map(workOrderDao::listByBusinessNo)
                .map(works -> works.stream().collect(Collectors.toMap(WorkOrderVO::getBusinessNo, WorkOrderVO::getWorkOrderId, (v1, v2) -> v1)))
                .orElse(Collections.emptyMap());
    }


    @Override
    public Integer queryCount(WorkOrderLogQueryDTO queryDTO) {
        return dispatchLogDao.queryCount(queryDTO);
    }

    @Override
    public List<DispatchLog> exportByTime(WorkOrderLogQueryDTO queryDTO) {
        Integer accountId = queryDTO.getAccountId();
        List<DispatchLog> logs = dispatchLogDao.exportByTime(queryDTO);
        List<AccountUser> list = accountUserService.getByType(accountId, false);
        PowerChangeMonitorConfig monitorConfig = Optional.ofNullable(monitorConfigMapper.selectById(accountId))
                .orElseGet(() -> new PowerChangeMonitorConfig().putDefaultValue(accountId));
        if (CollectionUtils.isNotEmpty(list)) {
            /**填充运维人员数据*/
            for (AccountUser a : list) {
                for (DispatchLog e : logs) {
                    if (a.getAccountUserId().equals(e.getAccountUserId())) {
                        e.setName(a.getName());
                        e.setPhone(a.getPhone());
                    }
                    e.setDispatchRange(monitorConfig.matchDispatchRange(e.getIdleTime()));
                }
            }
        }

        return logs;
    }


    @Override
    public List<ExportPowerLog> getByType(Integer accountId, Integer accountUserId, Long startTime, Long endTime, Integer rowCount, Integer pageNO, List<Integer> regionIdList, Integer type, Integer machineType) {
        HashMap<String, Object> params = new HashMap<>();
        params.put("accountId", accountId);
        params.put("accountUserId", accountUserId);
        params.put("startTime", new Date(startTime));
        params.put("endTime", new Date(endTime));
        params.put("regionIds", regionIdList);
        params.put("machineType", machineType);
        List<ExportPowerLog> logs = new ArrayList<>();
        List<ExportPowerLog> logDel = new ArrayList<>();
        List<ExportPowerLog> powerLogList = new LinkedList<>();
        if (type == 0) {
            /**获取条件符合的数据*/
            logs = dispatchLogDao.selectByType(params);
            /**查出所有的运维人员信息*/
            List<AccountUser> list = accountUserService.getByType(accountId, false);
            /**存入集合*/
            Map<Integer, AccountUser> map = new HashMap<>();
            for (AccountUser accountUser : list) {
                if (accountUser != null) {
                    map.put(accountUser.getAccountUserId(), accountUser);
                }
            }
            if (!NullUtils.isEmpty(logs)) {
                /**根据运维人员id分组*/
                logs.stream().filter(data -> data.getAccountUserId() != null).collect(Collectors.groupingBy(ExportPowerLog::getAccountUserId)).forEach((key, value) -> {
                    ExportPowerLog powerLog = new ExportPowerLog();
                    /**封装数据*/
                    for (ExportPowerLog exportPowerLog : value) {
                        powerLog.setAccountUserId(key);
                        AccountUser accountUser = map.get(exportPowerLog.getAccountUserId());
                        if (!NullUtils.isEmpty(accountUser)) {
                            if (key.equals(accountUser.getAccountUserId())) {
                                powerLog.setName(accountUser.getName());
                                powerLog.setPhone(accountUser.getPhone());
                            }
                        }

                        if (exportPowerLog.getIsValid() == WorkType.workOrder_UnValid) {
                            powerLog.setUnValid(exportPowerLog.getTotal());
                        }
                        if (exportPowerLog.getIsValid() == WorkType.workOrder_Valid) {
                            powerLog.setValid(exportPowerLog.getTotal());
                        }
                        if (exportPowerLog.getIsValid() == WorkType.workOrder_underReview) {
                            powerLog.setUnderReview(exportPowerLog.getTotal());
                        }
                    }
                    /**总数累加*/
                    powerLog.setTotal(powerLog.getValid() + powerLog.getUnValid() + powerLog.getUnderReview());
                    powerLogList.add(powerLog);
                });
                return powerLogList;
            }
        } else if (type == 1) {
            logs = dispatchLogDao.selectByTypeAndRegionId(params);
            /**查询某个运营区下所有的分区id*/
            List<Region> regionList = accountUserDao.getRegionId(accountId);
            Map<Integer, Region> map = new HashMap<>();
            if (regionList != null && regionList.size() > 0) {
                for (Region region : regionList) {
                    map.put(region.getRegionId(), region);
                }
            }
            if (!NullUtils.isEmpty(logs)) {
                logs.stream().filter(data -> data.getRegionId() != null).collect(Collectors.groupingBy(ExportPowerLog::getRegionId)).forEach((key, value) -> {
                    ExportPowerLog powerLog = new ExportPowerLog();
                    for (ExportPowerLog exportPowerLog : value) {
                        powerLog.setRegionId(key);
                        Region region = map.get(powerLog.getRegionId());
                        if (!NullUtils.isEmpty(region)) {
                            if (key.equals(region.getRegionId())) {
                                powerLog.setRegionName(region.getRegionName());
                            }
                        }

                        if (exportPowerLog.getIsValid() == WorkType.workOrder_UnValid) {
                            powerLog.setUnValid(exportPowerLog.getTotal());
                        }
                        if (exportPowerLog.getIsValid() == WorkType.workOrder_Valid) {
                            powerLog.setValid(exportPowerLog.getTotal());
                        }
                        if (exportPowerLog.getIsValid() == WorkType.workOrder_underReview) {
                            powerLog.setUnderReview(exportPowerLog.getTotal());
                        }
                    }
                    powerLog.setTotal(powerLog.getValid() + powerLog.getUnValid() + powerLog.getUnderReview());
                    powerLogList.add(powerLog);
                });
                return powerLogList;
            }
        }
        return powerLogList;
    }

    @Override
    public void updateAudit(MainLogAuditVo vo, LoginInfo login) {
        DispatchLog dispatchLogDb = dispatchLogDao.getTimeById(String.valueOf(vo.getLogId()));
        if (dispatchLogDb == null) {
            return;
        }
        if ( !checkIsNeedHandle(vo.getIsValid(), dispatchLogDb.getIsValid(), vo.getPerformance()) ) {
            return;
        }
        // 状态有变化，则更新。这里判断是为了过滤同时有效状态并且带有绩效值，但没必要修改状态的情况
        if (!Objects.equals(dispatchLogDb.getIsValid(), vo.getIsValid())) {
            dispatchLogUpdate(vo, login, dispatchLogDb);
        }

        // 有效改无效：删除现有绩效记录
        if (Objects.equals(vo.getIsValid(), WorkType.workOrder_UnValid)) {
            performanceService.removePerformance(dispatchLogDb.getDispatchLogId());
        }

        // 无效改有效
        if (Objects.equals(vo.getIsValid(), WorkType.workOrder_Valid)) {
            // 绩效开关是否开启
            if (!performanceService.checkSwitch(dispatchLogDb.getAccountId())) {
                return;
            }
            // 这个判断一下是否同时修改绩效值，如果有绩效值，则生成（或修改：如果已有绩效记录）一条绩效记录，并设置绩效值为当前传入的绩效值
            // 如果没有传绩效值，则是根据绩效配置生成绩效记录
            performanceService.generatePerformance(dispatchLogDb, vo.getPerformance());

        }
    }

    private static boolean checkIsNeedHandle(Integer voIsValid, Integer dbIsValid, BigDecimal performance) {
        // 要修改为无效，但当前已是无效，则返回
        if (Objects.equals(voIsValid, WorkType.workOrder_UnValid)
                && Objects.equals(dbIsValid, WorkType.workOrder_UnValid)) {
            return false;
        }
        // 要修改为有效，但当前已是有效，并且不修改绩效值，则返回
        if (Objects.equals(voIsValid, WorkType.workOrder_Valid)
                && Objects.equals(dbIsValid, WorkType.workOrder_Valid)
                && performance == null) {
            return false;
        }
        return true;
    }

    private void dispatchLogUpdate(MainLogAuditVo vo, LoginInfo login, DispatchLog dispatchLogDb) {
        Machine machine = new Machine();
        machine.setAccountid(dispatchLogDb.getAccountId());
        machine.setMachineid(dispatchLogDb.getMachineId());
        machine.setMachineno(dispatchLogDb.getMachineNO());
        machine.setUsercode(dispatchLogDb.getUserCode());

        machineOpLogService.batchAddRecord(
                "调度",
                String.format("变更状态[%d->%d]",
                        dispatchLogDb.getIsValid(),
                        vo.getIsValid()),
                true,
                "",
                Collections.singletonList(machine));

        DispatchLog dispatchLog = new DispatchLog();
        dispatchLog.setDispatchLogId(vo.getLogId());
        dispatchLog.setIsValid(vo.getIsValid());
        dispatchLog.setRemark(vo.getRemark());
        dispatchLog.setAuditName(login.getName());
        dispatchLog.setAuditorId(login.getAccountUserId());
        dispatchLog.setAuditTime(new Date());
        dispatchLogDao.amendAuditState(dispatchLog);
    }

    private void dispatchLogUpdate(MainLogAuditBatchVo vo, LoginInfo login, List<DispatchLog> dispatchLogs) {
        if (dispatchLogs == null || dispatchLogs.isEmpty()){
            return;
        }
        List<Machine> machineInfos = new ArrayList<>();
        List<Integer> dispatchLogIds = new ArrayList<>();
        dispatchLogs.forEach(dispatchLog -> {
            Machine machine = new Machine();
            machine.setAccountid(dispatchLog.getAccountId());
            machine.setMachineid(dispatchLog.getMachineId());
            machine.setMachineno(dispatchLog.getMachineNO());
            machine.setUsercode(dispatchLog.getUserCode());
            machineInfos.add(machine);
            dispatchLogIds.add(dispatchLog.getDispatchLogId());
        });
        machineOpLogService.batchAddRecord(
                "调度",
                String.format("变更状态[%d->%d]",
                        dispatchLogs.get(0).getIsValid(),
                        vo.getIsValid()),
                true,
                "",
                machineInfos);

        Map<String, Object> param = new HashMap<>();
        param.put("dispatchLogIds", dispatchLogIds);
        param.put("isValid", vo.getIsValid());
        param.put("remark", vo.getRemark());
        param.put("auditorId", login.getAccountUserId());
        param.put("auditName", login.getName());
        param.put("auditTime", new Date());
        dispatchLogDao.updateAuditState(param);
    }

    /**
     * 批量修改调度记录审核状态
     *
     * @param vo
     * @param login
     */
    public void auditOperationBatch(MainLogAuditBatchVo vo, LoginInfo login){
        if ( vo.getLogIds() == null || vo.getLogIds().isEmpty()){
            return;
        }
        // 获取调度记录
        List<DispatchLog> dispatchLogList = dispatchLogDao.getByIds(vo.getIds());
        if (dispatchLogList == null || dispatchLogList.isEmpty()){
            return;
        }
        List<DispatchLog> handleDispatchLogList = new ArrayList<>();
        List<DispatchLog> updateDispatchLogList = new ArrayList<>();
        dispatchLogList.forEach(dispatchLog -> {
            // 判断是否需要处理
            if(checkIsNeedHandle(vo.getIsValid(), dispatchLog.getIsValid(), vo.getPerformance())){
                handleDispatchLogList.add(dispatchLog);
            }
            // 状态有变化，则更新。这里判断是为了过滤同时有效状态并且带有绩效值，但没必要修改状态的情况
            if (!Objects.equals(dispatchLog.getIsValid(), vo.getIsValid())) {
                updateDispatchLogList.add(dispatchLog);
            }
        });
        if (!updateDispatchLogList.isEmpty()){
            // 更新调度记录
            dispatchLogUpdate(vo, login, updateDispatchLogList);
        }
        // 无效
        if (Objects.equals(vo.getIsValid(), WorkType.workOrder_UnValid) && !handleDispatchLogList.isEmpty()) {
            // 批量设置为无效。则把有效和审核中的都设置为无效。并删除绩效
            performanceService.removePerformance(handleDispatchLogList.stream().map(DispatchLog::getDispatchLogId).collect(Collectors.toList()));
        }
        // 有效
        if (Objects.equals(vo.getIsValid(), WorkType.workOrder_Valid) && !handleDispatchLogList.isEmpty()) {
            // 过滤出开启了绩效开关的区域id
            Set<Integer> onSwitchAccountIds = handleDispatchLogList
                    .stream()
                    .map(DispatchLog::getAccountId)
                    .distinct()
                    .filter(accountId -> performanceService.checkSwitch(accountId))
                    .collect(Collectors.toSet());
            // 过滤出开启了绩效开关的区域的调度记录，然后生成绩效
            List<DispatchLog> dispatchLogs = handleDispatchLogList.stream()
                    .filter(dispatchLog -> onSwitchAccountIds.contains(dispatchLog.getAccountId()))
                    .collect(Collectors.toList());
            performanceService.generatePerformance(dispatchLogs, vo.getPerformance());
        }
    }
}
